import json
from datetime import datetime, date, time
from decimal import Decimal
from enum import Enum

from sqlalchemy.orm.attributes import instance_dict

from common.datetime_util import datetime_to_str, time_to_str, date_to_str


def datetime_object_dumps_handler(obj):
    if isinstance(obj, datetime):
        return datetime_to_str(obj)
    if isinstance(obj, date):
        return date_to_str(obj)
    if isinstance(obj, time):
        return time_to_str(obj)
    elif isinstance(obj, Decimal):
        return str(obj)
    elif isinstance(obj, Enum):
        return obj.value
    else:
        raise TypeError("{}({}) is not JSON serializable".format(repr(obj), type(obj)))


def to_json(ins_dict):
    """
    python类型 -> json
    时间对象会转成 "2019-01-21T02:59:48"这种格式
    :param ins_dict:
    :return:
    """
    return json.dumps(ins_dict, default=datetime_object_dumps_handler, ensure_ascii=False)


def to_jsons(ins_dicts):
    return [to_json(ins_dict) for ins_dict in ins_dicts]


def to_dicts(orm_objs, id_replace=None, value_list=None, null_to_str: list = None, pop_list: list = None, add_keys: list = None):
    if value_list is None:
        value_list = []
    if not orm_objs:
        return []
    return [to_dict(orm_obj, id_replace, value_list, null_to_str=null_to_str, pop_list=pop_list, add_keys=add_keys)
            for orm_obj in orm_objs]


def to_dict(orm_obj, id_replace=None, value_list=None, null_to_str: list = None, pop_list: list = None, add_keys: list = None):
    if isinstance(orm_obj, dict):
        return orm_obj
    if isinstance(orm_obj, str):
        return orm_obj
    new_orm_obj_s = []
    if hasattr(orm_obj, "_asdict"):
        if len(orm_obj) > 1:
            new_orm_obj_s = list(orm_obj)
            orm_obj = orm_obj[0]


    if value_list is None:
        value_list = []
    if pop_list is None:
        pop_list = []
    if not orm_obj:
        return {}
    dict_obj = get_instance_dict_copy_recursive(orm_obj)

    if value_list:
        dict_obj_tmp = dict()
        # 使用for循环可以保证dict转json后key的顺序和value_list里key的顺序一致
        for key_need in value_list:
            dict_obj_tmp.update({key_need: dict_obj.get(key_need)} if key_need in dict_obj else {})
        dict_obj = dict_obj_tmp

    if id_replace and "id" in dict_obj:
        dict_obj[id_replace] = dict_obj["id"]
        del (dict_obj["id"])
    if null_to_str:
        for key in null_to_str:
            if key in dict_obj.keys():
                if not dict_obj[key]:
                    dict_obj[key] = ''
    for pop_key in pop_list:
        if pop_key in dict_obj:
            del (dict_obj[pop_key])
    if add_keys and len(add_keys) == (len(new_orm_obj_s) - 1):
        i = 1
        for add_key in add_keys:
            dict_obj[add_key] = to_dict(new_orm_obj_s[i])
            i = i + 1


    return dict_obj


def get_instance_dict_copy_recursive(obj):
    if not hasattr(obj, "__dict__"):
        return obj
    elif not type(obj) == dict:
        dict_obj = instance_dict(obj).copy()
    else:
        dict_obj = obj

    if '_sa_instance_state' in dict_obj:
        dict_obj.pop('_sa_instance_state')

    for key, value in dict_obj.copy().items():
        if isinstance(value, Enum):
            value = value.value
            dict_obj[key] = value
        if isinstance(value, list):
            sub_dict_obj_s = []

            for item in value:
                sub_dict_obj = get_instance_dict_copy_recursive(item)
                sub_dict_obj_s.append(sub_dict_obj)

            dict_obj[key] = sub_dict_obj_s
        else:
            value_is_sa_obj = hasattr(value, '_sa_instance_state')

            if value_is_sa_obj:
                sub_dict_obj = get_instance_dict_copy_recursive(value)
                dict_obj[key] = sub_dict_obj

    return dict_obj


def dict_pop_empty_data(**kwargs):
    for key in list(kwargs.keys()):
        if kwargs[key] is None:
            kwargs.pop(key)
    return kwargs


def to_dict_with_key(orm_objs, key, index=None):
    if not orm_objs:
        return {}
    return_dict = {}

    for orm_obj in orm_objs:
        if index is not None:
            dict_obj = get_instance_dict_copy_recursive(orm_obj[index])
        else:
            dict_obj = get_instance_dict_copy_recursive(orm_obj)
        return_dict[dict_obj.get(key)] = dict_obj
    return return_dict


def to_dict_group_with_key(orm_objs, key, index=None):
    if not orm_objs:
        return {}
    return_dict = {}

    for orm_obj in orm_objs:
        if index is not None:
            dict_obj = get_instance_dict_copy_recursive(orm_obj[index])
        else:
            dict_obj = get_instance_dict_copy_recursive(orm_obj)
        if dict_obj.get(key) in return_dict:
            return_dict[dict_obj.get(key)].append(dict_obj)
        else:
            return_dict[dict_obj.get(key)] = [dict_obj]
    return return_dict
